package com.codedancer.campus.manager.service.impl;

import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.MqSendMessageUtil;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.enums.LostFoundItemStatus;
import com.codedancer.campus.enums.LostFoundItemType;
import com.codedancer.campus.enums.SystemMessageType;
import com.codedancer.campus.manager.service.ILostFoundItemService;
import com.codedancer.campus.manager.service.bo.lostFoundItem.LostFoundItemExamineBo;
import com.codedancer.campus.manager.service.bo.lostFoundItem.LostFoundItemPageSearchBo;
import com.codedancer.campus.manager.service.excel.LostFoundItemExcel;
import com.codedancer.campus.manager.service.model.SystemMessageMqParamModel;
import com.codedancer.campus.manager.service.vo.lostFoundItem.LostFoundItemPageVo;
import com.codedancer.campus.manager.service.vo.lostFoundItem.LostFoundItemVo;
import com.codedancer.campus.mapper.CategoryMapper;
import com.codedancer.campus.mapper.LostFoundItemExamineRecordMapper;
import com.codedancer.campus.mapper.LostFoundItemImageMapper;
import com.codedancer.campus.mapper.LostFoundItemMapper;
import com.codedancer.campus.mapper.SystemMessageMapper;
import com.codedancer.campus.mapper.UserFollowMapper;
import com.codedancer.campus.mapper.UserMapper;
import com.codedancer.campus.po.Category;
import com.codedancer.campus.po.LostFoundItem;
import com.codedancer.campus.po.LostFoundItemExamineRecord;
import com.codedancer.campus.po.LostFoundItemImage;
import com.codedancer.campus.po.User;
import com.codedancer.campus.qo.lostFoundItem.LostFoundItemPageSearchQo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class LostFoundItemServiceImpl implements ILostFoundItemService {

    @Autowired
    private LostFoundItemMapper lostFoundItemMapper;
    @Autowired
    private LostFoundItemImageMapper lostFoundItemImageMapper;
    @Autowired
    private SystemMessageMapper systemMessageMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private LostFoundItemExamineRecordMapper lostFoundItemExamineRecordMapper;
    @Autowired
    private UserFollowMapper userFollowMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MqSendMessageUtil mqSendMessageUtil;

    /**
     * 分页查询物品
     *
     * @param lostFoundItemPageSearchBo
     * @return
     */
    @Override
    public IPage<LostFoundItemPageVo> page(LostFoundItemPageSearchBo lostFoundItemPageSearchBo) {
        LostFoundItemPageSearchQo lostFoundItemPageSearchQo = BeanUtil.copyProperties(
            lostFoundItemPageSearchBo, LostFoundItemPageSearchQo.class);
        IPage<LostFoundItem> lostFoundItemIPage = lostFoundItemMapper.page2Manager(
            new Page<LostFoundItem>(lostFoundItemPageSearchBo.getPage(),
                lostFoundItemPageSearchBo.getSize()), lostFoundItemPageSearchQo);
        IPage<LostFoundItemPageVo> lostFoundItemPageVoIPage = new Page<>();
        List<LostFoundItemPageVo> lostFoundItemPageVos;
        lostFoundItemPageVos = lostFoundItemIPage.getRecords().stream().map(lostFoundItem -> {
            LostFoundItemPageVo lostFoundItemPageVo = BeanUtil.copyProperties(lostFoundItem,
                LostFoundItemPageVo.class);
            lostFoundItemPageVo.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
            lostFoundItemPageVo.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
            lostFoundItemPageVo.setCategoryName(lostFoundItem.getCategory().getName());
            return lostFoundItemPageVo;
        }).collect(Collectors.toList());
        lostFoundItemPageVoIPage.setRecords(lostFoundItemPageVos);
        lostFoundItemPageVoIPage.setTotal(lostFoundItemIPage.getTotal());
        return lostFoundItemPageVoIPage;
    }

    /**
     * 详情
     *
     * @param uuid
     * @return
     */
    @Override
    public LostFoundItemVo detail(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.detail(uuid);
        if (ObjectUtil.isEmpty(lostFoundItem)) {
            throw new BusinessException("物品不存在");
        }
        LostFoundItemVo lostFoundItemVo = BeanUtil.copyProperties(lostFoundItem,
            LostFoundItemVo.class);
        lostFoundItemVo.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
        lostFoundItemVo.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
        // 获取图片信息
        List<LostFoundItemImage> lostFoundItemImages = lostFoundItemImageMapper.selectListByColumn(
            "lost_found_item_uuid", lostFoundItem.getUuid());
        lostFoundItemVo.setImages(
            lostFoundItemImages.stream().map(LostFoundItemImage::getImageUrl).collect(
                Collectors.toList()));
        Category category = categoryMapper.selectById(lostFoundItem.getCategoryUuid());
        lostFoundItemVo.setCategoryName(category.getName());
        // 查询最近一条审核记录
        LostFoundItemExamineRecord lostFoundItemExamineRecord = lostFoundItemExamineRecordMapper
            .selectLastExamineRecord(uuid);
        if (ObjectUtil.isNotEmpty(lostFoundItemExamineRecord)
            && !lostFoundItemExamineRecord.getIsPass()) {
            lostFoundItemVo.setLastNoPassReason(lostFoundItemExamineRecord.getNoPassReason());
        }
        return lostFoundItemVo;
    }

    /**
     * 审核未通过
     *
     * @param lostFoundItemExamineBo
     */
    @Override
    public void noPass(LostFoundItemExamineBo lostFoundItemExamineBo) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(lostFoundItemExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("物品不存在"));
        if (ObjectUtil.isEmpty(lostFoundItemExamineBo.getNoPassReason())) {
            throw new BusinessException("请输入原因");
        }
        // 判断审核次数是否大于5次
        if (lostFoundItem.getExamineCount() > 5) {
            throw new BusinessException("审核次数已到上限5次");
        }
        lostFoundItem.setExamineCount(lostFoundItem.getExamineCount() + 1);
        lostFoundItem.setStatus(LostFoundItemStatus.NOT_PASS);
        lostFoundItemMapper.updateById(lostFoundItem);
        // 保存审核记录
        LostFoundItemExamineRecord lostFoundItemExamineRecord = LostFoundItemExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .lostFoundItemUuid(lostFoundItem.getUuid())
            .examineAdminUuid(lostFoundItemExamineBo.getCurrentUserUuid())
            .noPassReason(lostFoundItemExamineBo.getNoPassReason())
            .isPass(false)
            .build();
        lostFoundItemExamineRecordMapper.insert(lostFoundItemExamineRecord);
        // 保存系统消息记录
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.LOST_FOUND_ITEM_EXAMINE)
            .isPass(false)
            .receiveUserUuid(lostFoundItem.getPublishUserUuid())
            .content(
                "【" + lostFoundItem.getName() + "】未审核通过，未通过原因：" + lostFoundItemExamineBo
                    .getNoPassReason()).build();
        mqSendMessageUtil.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
    }

    /**
     * 审核通过
     *
     * @param lostFoundItemExamineBo
     */
    @Override
    public void pass(LostFoundItemExamineBo lostFoundItemExamineBo) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(lostFoundItemExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("物品不存在"));
        User user = userMapper.selectById(lostFoundItem.getPublishUserUuid());
        // 判断审核次数是否大于5次
        if (lostFoundItem.getExamineCount() > 5) {
            throw new BusinessException("审核次数已到上限5次");
        }
        lostFoundItem.setExamineCount(lostFoundItem.getExamineCount() + 1);
        // 判断物品发布类型
        if (lostFoundItem.getType().equals(LostFoundItemType.PICK_UP)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_CLAIM);
        }
        if (lostFoundItem.getType().equals(LostFoundItemType.LOST)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_FOUND);
        }
        lostFoundItemMapper.updateById(lostFoundItem);
        // 保存审核记录
        LostFoundItemExamineRecord lostFoundItemExamineRecord = LostFoundItemExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .lostFoundItemUuid(lostFoundItem.getUuid())
            .examineAdminUuid(lostFoundItemExamineBo.getCurrentUserUuid())
            .isPass(true)
            .build();
        lostFoundItemExamineRecordMapper.insert(lostFoundItemExamineRecord);
        // 保存系统消息记录
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.LOST_FOUND_ITEM_EXAMINE)
            .isPass(true)
            .receiveUserUuid(lostFoundItem.getPublishUserUuid())
            .content(
                "【" + lostFoundItem.getName() + "】审核通过").build();
        mqSendMessageUtil.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
        // 给粉丝推送消息
        SystemMessageMqParamModel commodityPublishSystemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .lostFoundItemPublishUserUuid(lostFoundItem.getPublishUserUuid())
            .messageType(SystemMessageType.LOST_FOUND_ITEM_PUBLISH).build();
        mqSendMessageUtil.sendSystemMessage(
            JSONUtil.toJsonStr(commodityPublishSystemMessageMqParamModel));
    }

    /**
     * 发布
     *
     * @param uuid
     */
    @Override
    public void publish(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        // 判断物品发布类型
        if (lostFoundItem.getType().equals(LostFoundItemType.PICK_UP)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_CLAIM);
        }
        if (lostFoundItem.getType().equals(LostFoundItemType.LOST)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_FOUND);
        }
        lostFoundItem.setIsAdminRevoke(false);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 撤回
     *
     * @param uuid
     */
    @Override
    public void revoke(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        lostFoundItem.setStatus(LostFoundItemStatus.RECALL);
        lostFoundItem.setIsAdminRevoke(true);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 删除
     *
     * @param uuid
     */
    @Override
    public void delete(String uuid) {
        lostFoundItemMapper.deleteById(uuid);
    }

    /**
     * 导出物品
     *
     * @param request
     * @param response
     * @param lostFoundItemPageSearchBo
     */
    @Override
    public void export(HttpServletRequest request, HttpServletResponse response,
        LostFoundItemPageSearchBo lostFoundItemPageSearchBo) {
        log.info("开始导出物品");
        LostFoundItemPageSearchQo lostFoundItemPageSearchQo = BeanUtil
            .copyProperties(lostFoundItemPageSearchBo, LostFoundItemPageSearchQo.class);
        // 获取需要导出的物品
        List<LostFoundItem> lostFoundItems = lostFoundItemMapper
            .listExportLostFoundItem(lostFoundItemPageSearchQo);
        // 组装数据
        List<LostFoundItemExcel> lostFoundItemExcels = assembleData(lostFoundItems);
        Map<String, Object> map = new HashMap<>();
        ExportParams params = new ExportParams("物品列表", "物品列表", ExcelType.HSSF);
        map.put(NormalExcelConstants.DATA_LIST, lostFoundItemExcels);
        map.put(NormalExcelConstants.CLASS, LostFoundItemExcel.class);
        map.put(NormalExcelConstants.PARAMS, params);
        map.put(NormalExcelConstants.FILE_NAME, "物品列表" + DateUtil.today());
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
        log.info("物品导出完成");
    }

    /**
     * 批量撤回
     *
     * @param uuids
     */
    @Override
    public void batchRevoke(List<String> uuids) {
        for (String uuid : uuids) {
            LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
                .orElseThrow(() -> new BusinessException("物品不存在，uuid：" + uuid));
            // 判断物品是否处于未找到或者未认领状态
            if (!lostFoundItem.getStatus().equals(LostFoundItemStatus.NO_CLAIM) && !lostFoundItem
                .getStatus().equals(LostFoundItemStatus.NO_FOUND)) {
                throw new BusinessException(
                    "物品状态未处于未找到或者未认领状态，物品名称：" + lostFoundItem.getName());
            }
            lostFoundItem.setIsAdminRevoke(true);
            lostFoundItem.setStatus(LostFoundItemStatus.RECALL);
            lostFoundItemMapper.updateById(lostFoundItem);
        }
    }

    /**
     * 批量发布
     *
     * @param uuids
     */
    @Override
    public void batchPublish(List<String> uuids) {
        for (String uuid : uuids) {
            LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
                .orElseThrow(() -> new BusinessException("物品不存在，uuid：" + uuid));
            // 判断物品是否处于撤回状态
            if (!lostFoundItem.getStatus().equals(LostFoundItemStatus.RECALL)) {
                throw new BusinessException(
                    "物品状态未处于撤回状态，物品名称：" + lostFoundItem.getName());
            }
            // 判断物品发布类型
            if (lostFoundItem.getType().equals(LostFoundItemType.PICK_UP)) {
                lostFoundItem.setStatus(LostFoundItemStatus.NO_CLAIM);
            }
            if (lostFoundItem.getType().equals(LostFoundItemType.LOST)) {
                lostFoundItem.setStatus(LostFoundItemStatus.NO_FOUND);
            }
            lostFoundItem.setIsAdminRevoke(false);
            lostFoundItemMapper.updateById(lostFoundItem);
        }
    }

    /**
     * 批量删除
     *
     * @param uuids
     */
    @Override
    public void batchDelete(List<String> uuids) {
        lostFoundItemMapper.deleteBatchIds(uuids);
    }

    /**
     * 组装导出excel数据
     *
     * @param lostFoundItems
     * @return
     */
    private List<LostFoundItemExcel> assembleData(List<LostFoundItem> lostFoundItems) {
        return lostFoundItems.stream().map(lostFoundItem -> {
            LostFoundItemExcel lostFoundItemExcel = BeanUtil
                .copyProperties(lostFoundItem, LostFoundItemExcel.class);
            lostFoundItemExcel.setCategoryName(lostFoundItem.getCategory().getName());
            lostFoundItemExcel.setPublishTypeName(lostFoundItem.getType().getName());
            lostFoundItemExcel.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
            lostFoundItemExcel.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
            lostFoundItemExcel.setStatus(lostFoundItem.getStatus().getName());
            return lostFoundItemExcel;
        }).collect(Collectors.toList());
    }
}
